package com.ruoyi.system.controller;

import com.ruoyi.common.core.constant.SecurityConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.poi.ExcelUtil;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.core.web.page.TableDataInfo;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.common.security.annotation.InnerAuth;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.RemoteFileService;
import com.ruoyi.system.api.domain.File;
import com.ruoyi.system.api.domain.FileData;
import com.ruoyi.system.api.domain.FileObject;
import com.ruoyi.system.api.domain.SysFile;
import com.ruoyi.system.api.model.LoginUser;
import com.ruoyi.system.domain.FileAuth;
import com.ruoyi.system.domain.FileRecord;
import com.ruoyi.system.service.IFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/**
 * 附件Controller
 *
 * @author ruoyi
 * @date 2023-02-22
 */
@Api(tags = "附件")
@RestController
@RequestMapping("/file")
public class FileController extends BaseController {
    @Autowired
    private IFileService fileService;

    @Autowired
    private RemoteFileService remoteFileService;

    /**
     * 查询附件列表
     */
    @RequiresPermissions("system:file:list")
    @GetMapping("/list")
    @ApiOperation(value = "查询附件列表", response = File.class)
    public TableDataInfo list(File file) {
        startPage();
        List<File> list = fileService.selectFileList(file);
        return getDataTable(list);
    }

    @GetMapping("/dataList")
    @ApiOperation(value = "查询文件数据列表", response = FileData.class)
    public AjaxResult list(FileData fileData) {
        List<FileData> list = fileService.selectFileDataList(fileData);
        return success(list);
    }

    @GetMapping("/page/dataList")
    @ApiOperation(value = "查询文件数据列表", response = FileData.class)
    public TableDataInfo pageDataList(FileData fileData) {
        startPage();
        List<FileData> list = fileService.selectFileDataList(fileData);
        return getDataTable(list);
    }

    /**
     * 导出附件列表
     */
    @RequiresPermissions("system:file:export")
    @Log(title = "附件", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ApiOperation(value = "导出文件列表")
    public void export(HttpServletResponse response, File file) {
        List<File> list = fileService.selectFileList(file);
        ExcelUtil<File> util = new ExcelUtil<File>(File.class);
        util.exportExcel(response, list, "附件数据");
    }

    /**
     * 获取附件详细信息
     */
    @GetMapping(value = "/detail/{fileId}")
    @ApiOperation(value = "查询文件详情", response = File.class)
    public AjaxResult getInfo(@ApiParam(value = "附件id", required = true) @PathVariable("fileId") Long fileId) {
        File file = fileService.selectFileByFileId(fileId);
        return success(fileService.selectFileByFileId(fileId));
    }

    /**
     * 获取附件列表(不分页)
     */
    @GetMapping()
    @ApiOperation(value = "查询文件列表", response = File.class)
    public AjaxResult selectFileList(File file) {
        return success(fileService.selectFileList(file));
    }

    /**
     * 获取附件数据列表
     */
    @InnerAuth
    @GetMapping(value = "/remote/data")
    @ApiOperation(value = "获取附件数据列表（远程接口）", response = FileData.class)
    public AjaxResult selectRemoteFileDataList(@ApiParam(value = "文件组id", required = false) @RequestParam("groupId") Long groupId, @ApiParam(value = "文件类型", required = false) @RequestParam(value = "fileTypes") String fileTypes) {
        return success(fileService.selectFileDataListByGroupId(groupId, fileTypes));
    }

    /**
     * 获取附件数据详细信息
     */
    @GetMapping(value = "/data/{dataId}")
    @ApiOperation(value = "获取附件数据信息", response = FileData.class)
    public AjaxResult getFileData(@ApiParam(value = "文件数据id", required = true) @PathVariable("dataId") Long dataId) {
        return success(fileService.selectFileDataBYDataId(dataId));
    }

    /**
     * 上传文件
     */
    @Log(title = "上传文件", businessType = BusinessType.INSERT)
    @PostMapping("/upload")
    @ApiOperation(value = "上传文件", response = File.class)
    public AjaxResult upload(File uploadFile) {
        try {
            MultipartFile file = uploadFile.getFile();
            if (file != null) {
                LoginUser loginUser = SecurityUtils.getLoginUser();
                String extension = FileTypeUtils.getExtension(file);
                R<SysFile> fileResult = remoteFileService.upload(file, uploadFile.getAuthId());
                if (fileResult.getCode() != 200) {
                    return error("文件服务异常，请联系管理员");
                }
                File fileData = new File();
                fileData.setFileName(file.getOriginalFilename());
                fileData.setFilePath(fileResult.getData().getUrl());
                fileData.setOrgId(SecurityUtils.getOrgId());
                fileData.setUserId(SecurityUtils.getUserId());
                fileData.setDownloadUrl(fileResult.getData().getDownloadUrl());
                fileData.setGroupId(0L);
                fileData.setFileSizeDisplay(fileResult.getData().getDisplaySize());
                fileData.setFileSize(file.getSize());
                fileService.insertFile(fileData);
                File returnFileData = new File();
                returnFileData.setFileId(fileData.getFileId());
                returnFileData.setFileSizeDisplay(fileData.getFileSizeDisplay());
                returnFileData.setFileName(file.getOriginalFilename());
                returnFileData.setDownloadUrl(fileData.getDownloadUrl());
                return success(returnFileData);
            } else
                return warn("上传文件不能为空!");
        } catch (Exception e) {
            logger.error(e.getMessage());
            return error("上传文件异常，请联系管理员");
        }
    }

    /**
     * 保存并上传文件
     */
    @Log(title = "保存并上传文件", businessType = BusinessType.INSERT)
    @PostMapping("/autoUpload")
    @ApiOperation(value = "保存并上传文件", response = File.class)
    public AjaxResult autoUpload(File fileData) {
        try {
            MultipartFile file = fileData.getFile();
            if (!file.isEmpty()) {
                R<SysFile> fileResult = remoteFileService.upload(file, fileData.getAuthId());
                if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) {
                    return error("文件服务异常，请联系管理员");
                }
                fileData.setFileName(file.getOriginalFilename());
                fileData.setFilePath(fileResult.getData().getUrl());
                fileData.setDownloadUrl(fileResult.getData().getDownloadUrl());
                if (SecurityUtils.getOrgId() != null && SecurityUtils.getOrgId().longValue() != 0) {
                    fileData.setOrgId(SecurityUtils.getOrgId());
                    fileData.setUserId(SecurityUtils.getUserId());
                }
                fileData.setFileSizeDisplay(fileResult.getData().getDisplaySize());
                fileData.setFileSize(file.getSize());
                fileService.insertFile(fileData);
                File returnFileData = new File();
                returnFileData.setFileId(fileData.getFileId());
                returnFileData.setFileSizeDisplay(fileData.getFileSizeDisplay());
                returnFileData.setFileName(file.getOriginalFilename());
                return success(returnFileData);
            } else
                return warn("上传文件不能为空!");
        } catch (Exception e) {
            logger.error(e.getMessage());
            return error("上传文件异常，请联系管理员");
        }
    }

    /**
     * 上传postOffice文件
     */
    @InnerAuth
    @Log(title = "保存并上传文件", businessType = BusinessType.INSERT)
    @PostMapping("/autoUpload/fileSave")
    @ApiOperation(value = "上传postOffice文件(内部请求)", response = File.class)
    public AjaxResult autoUploadFileSave(File fileData) {
        try {
            MultipartFile file = fileData.getFile();
            if (!file.isEmpty()) {
                R<SysFile> fileResult = remoteFileService.upload(file, fileData.getAuthId());
                if (StringUtils.isNull(fileResult) || StringUtils.isNull(fileResult.getData())) {
                    return error("文件服务异常，请联系管理员");
                }
                if (fileData.getFileName() == null) {
                    fileData.setFileName(file.getOriginalFilename());
                }
                fileData.setFilePath(fileResult.getData().getUrl());
                fileData.setDownloadUrl(fileResult.getData().getDownloadUrl());
//                if(SecurityUtils.getOrgId() != null && SecurityUtils.getOrgId().longValue() != 0) {
                fileData.setOrgId(SecurityUtils.getOrgId());
                fileData.setUserId(SecurityUtils.getUserId());
//                }
                fileData.setFileSizeDisplay(fileResult.getData().getDisplaySize());
                fileData.setFileSize(file.getSize());
                fileService.insertFile(fileData);
                File returnFileData = new File();
                returnFileData.setFileId(fileData.getFileId());
                returnFileData.setFileSizeDisplay(fileData.getFileSizeDisplay());
                returnFileData.setFileName(file.getOriginalFilename());
                return success(returnFileData);
            } else
                return warn("上传文件不能为空!");
        } catch (Exception e) {
            logger.error(e.getMessage());
            return error("上传文件异常，请联系管理员");
        }
    }


    /**
     * 下载文件
     */
    @Log(title = "下载文件", businessType = BusinessType.INSERT)
    @GetMapping("/download/{fileId}")
    @ApiOperation(value = "根据文件id下载文件")
    public void download(HttpServletResponse response, @ApiParam(value = "附件id", required = true) @PathVariable("fileId") Long fileId) throws IOException {
        File file = fileService.selectFileByFileId(fileId);
        if(file == null){
            logger.error("未查找到fileId:" + fileId);
            return;
        }
        R<byte[]> fileResult = remoteFileService.download("", file.getFilePath());
        if (fileResult.getCode() != 200) {
            return;
        }
        byte[] fileData = fileResult.getData();
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getFileName() + "\"");
        response.addHeader("Content-Length", "" + fileData.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(fileData, response.getOutputStream());
    }

    /**
     * 下载文件
     */
    @Log(title = "下载文件", businessType = BusinessType.INSERT)
    @GetMapping("/download/auth/{fileId}")
    @ApiOperation(value = "根据文件id下载文件")
    public AjaxResult downloadAuth(HttpServletResponse response, @ApiParam(value = "附件id", required = true) @PathVariable("fileId") Long fileId) throws IOException {
        File file = fileService.selectFileByFileId(fileId);
        String errorMsg = fileService.download(file, response);
        if (errorMsg != null) {
            return error(errorMsg);
        }
        return success("操作成功");
    }

    /**
     * 下载文件
     */
    @InnerAuth
    @Log(title = "获取需要下载文件的byte流", businessType = BusinessType.EXPORT)
    @GetMapping("/fileBytes/{fileId}")
    @ApiOperation(value = "根据文件id下载文件(内部请求)")
    public R<byte[]> fileBytes(HttpServletResponse response, @ApiParam(value = "附件id", required = true) @PathVariable("fileId") Long fileId) throws IOException {
        File file = fileService.selectFileByFileId(fileId);
        R<byte[]> fileResult = remoteFileService.download("", file.getFilePath());
        return fileResult;
    }

    /**
     * 下载文件
     */
    @InnerAuth
    @Log(title = "获取需要下载文件的byte流", businessType = BusinessType.EXPORT)
    @GetMapping("/fileBytesByGroup/{groupId}")
    @ApiOperation(value = "根据文件id下载文件(内部请求)")
    public R<List<byte[]>> fileBytesByGroup(HttpServletResponse response, @ApiParam(value = "附件id", required = true) @PathVariable("groupId") Long groupId) throws IOException {
        File queryFile = new File();
        queryFile.setGroupId(groupId);
        List<File> fileList = fileService.selectFileList(queryFile);
        List<byte[]> byteList = new ArrayList<>();
        for (File file : fileList) {
            R<byte[]> fileResult = remoteFileService.download("", file.getFilePath());
            if (fileResult.getCode() == 200) {
                byteList.add(fileResult.getData());
            }
        }
        return R.ok(byteList);
    }

    /**
     * 下载文件
     */
    @Log(title = "下载文件", businessType = BusinessType.INSERT)
    @GetMapping("/download")
    @ApiOperation(value = "根据文件名称下载文件")
    public void download(HttpServletResponse response, @ApiParam(value = "文件名称", required = true) @RequestParam("fileName") String fileName) throws IOException {
        R<byte[]> fileResult = remoteFileService.download("", fileName);
        byte[] fileData = fileResult.getData();
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        response.addHeader("Content-Length", "" + fileData.length);
        response.setContentType("application/octet-stream; charset=UTF-8");
        IOUtils.write(fileData, response.getOutputStream());

    }

    /**
     * 新增附件
     */
    @InnerAuth
    @Log(title = "附件", businessType = BusinessType.INSERT)
    @PostMapping
    @ApiOperation(value = "新增附件(内部请求)")
    public AjaxResult add(@RequestParam("groupId") Long groupId, @RequestParam("typeId") Integer typeId, @RequestParam("fileIds") List<Long> fileIds) {
        return toAjax(fileService.saveFile(groupId, typeId, fileIds));
    }

    /**
     * 新增附件
     */
    @InnerAuth
    @Log(title = "附件", businessType = BusinessType.INSERT)
    @PostMapping("/fileData")
    @ApiOperation(value = "新增附件数据(内部请求)")
    public AjaxResult add(@RequestBody FileObject fileObject) {
        return toAjax(fileService.saveFileDataList(fileObject));
    }

    @Log(title = "附件", businessType = BusinessType.INSERT)
    @PostMapping("/saveFile")
    @ApiOperation(value = "新增附件")
    public AjaxResult saveFile(@RequestBody File file) {
        return toAjax(fileService.saveFile(file));
    }

    @InnerAuth
    @Log(title = "远程保存附件", businessType = BusinessType.INSERT)
    @PostMapping("/remote/saveFile")
    @ApiOperation(value = "新增附件")
    public R saveRemoteFile(@RequestBody File file) {
        int rows = fileService.saveFile(file);
        if(rows == 0){
            return R.fail("未找到需要保存的文件");
        }
        return R.ok();
    }

    @Log(title = "附件", businessType = BusinessType.INSERT)
    @PostMapping("/saveFileData")
    @ApiOperation(value = "新增附件数据")
    public AjaxResult add(@RequestBody FileData fileData) {
        return toAjax(fileService.saveFileData(fileData));
    }


    /**
     * 删除附件
     */
    @Log(title = "附件", businessType = BusinessType.DELETE)
    @DeleteMapping("/delete/{fileIds}")
    @ApiOperation(value = "删除附件")
    public AjaxResult remove(@ApiParam(value = "附件id", required = true) @PathVariable Long[] fileIds) {
        return toAjax(fileService.deleteFileByFileIds(fileIds));
    }

    /**
     * 删除附件
     */
    @Log(title = "附件", businessType = BusinessType.DELETE)
    @DeleteMapping("/delete/contract/{fileId}")
    @ApiOperation(value = "删除附件")
    @InnerAuth
    public AjaxResult removeFile(@ApiParam(value = "附件id", required = true) @PathVariable Long fileId) {
        return toAjax(fileService.removeFile(fileId));
    }

    /**
     * 删除附件数据
     */
    @Log(title = "附件数据", businessType = BusinessType.DELETE)
    @DeleteMapping("/data/delete/{dataIds}")
    @ApiOperation(value = "删除附件数据")
    public AjaxResult removeFileData(@ApiParam(value = "附件数据id", required = true) @PathVariable String[] dataIds) {
        return toAjax(fileService.deleteFileDataByDataId(dataIds));
    }

    /**
     * * 添加文件权限
     *
     * @param fileAuth
     * @return
     */
    @Log(title = "添加文件权限", businessType = BusinessType.INSERT)
    @PostMapping("/addFileAuth")
    @ApiOperation(value = "添加文件权限")
    public AjaxResult addFileAuth(@RequestBody FileAuth fileAuth) {
        return toAjax(fileService.addFileAuth(fileAuth));
    }

    /**
     * 获取文件下载记录列表
     */
    @GetMapping(value = "/record/list")
    @ApiOperation(value = "获取文件下载记录列表", response = FileRecord.class)
    public TableDataInfo selectFileRecordList(FileRecord fileRecord) {
        startPage();
        return getDataTable(fileService.selectFileRecordList(fileRecord));
    }

    @InnerAuth
    @Log(title = "分割文件", businessType = BusinessType.UPDATE)
    @PutMapping(value = "/splitFileList")
    @ApiOperation(value = "分割文件列表", response = FileRecord.class)
    public R<Integer> replaceFileList(@RequestBody File file) {
        return R.ok(fileService.splitFileList(file));
    }

    @InnerAuth
    @Log(title = "根据流程实例删除文件", businessType = BusinessType.DELETE)
    @DeleteMapping(value = "/remote/deleleByProcInsId")
    public R<Integer> deleleByProcInsId(@RequestBody File file) {
        return R.ok(fileService.deleteFileByProcInsId(file));
    }

}
